<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>高级技巧</title>
</head>
<body>
<button>点击</button>
</body>
<script>
    /*
    * 深浅拷贝:
    *   1. 直接赋值是浅拷贝
    *   2. 深拷贝需要用不同的赋值方案
    *      拷贝对象:
    *        (1) 展开运算符 --- const objNew = {...objOld}
    *        (2) 对象方法 --- Object.assign(objNew , objOld)
    *      拷贝数组:
    *        (1) 展开运算符 --- const ArrayNew = {...ArrayOld}
    * */
    const obj = {
        name: 'black' ,
        age: 18
    }
    // 对象拷贝
    // 浅拷贝
    const o = obj
    const o1 = Object.assign(obj)
    console.log(o1)
    // 深拷贝
    const o2 = {...obj}
    const o3 = {}
    Object.assign(o3 , obj)
    o2.task = '{...obj}'
    o3.task = 'Object.assign(objNew , objOld)'
    console.log(o1)
    console.log(o2)
    console.log(o3)
    // 超深拷贝
    const objj = {
        uname: 'pink',
        age: 18,
        hobby: ['乒乓球' , '羽毛球'],
        family: {
            baby: '小pink'
        }
    }
    // 通过递归函数进行拷贝
        //     略
    // 通过JS库的lodash里面cloneDeep内部实现了深拷贝
        //     略
    // 通过JSON实现深拷贝
    const hold = JSON.stringify(objj) // 把对象转换成JSON字符串
    console.log(hold)
    const newObjj = JSON.parse(hold) // 把JSON字符串转换成对象
    console.log(newObjj)
    // 简化书写
    console.log(JSON.parse(JSON.stringify(objj)))
    /*
    * 关于this的指向问题
    *   普通函数的this指向
    *       谁调用我我就指向谁
    *
    *   箭头函数的this指向
    *       箭头函数的this会默认绑定外层this的值,在箭头函数中this的值和外层的this是一样的
    *       箭头函数中的this引用的就是最近作用域中的this
    *       向外层作用域中一层一层查找this,直到有this的定义为止
    *
    *   改变this指向
    *       1.call(thisArg , arg1 , arg2 , ...)
    *           thisArg: 在fun函数运行时指定this的值
    *           arg1 , arg2: 传递的其他参数
    *           返回值就是函数的返回值,因为它就是调用函数
    *
    *       2.apply(thisArg , [argsArray])
    *           thisArg: 在fun函数运行时指定的this的值
    *           argsArray: 传递的值,必须包含在数组里面
    *           返回值就是函数的返回值,因为它就是调用函数
    * */
    /*
    * bind()方法不会调用函数,但是能改变函数内部的this指向
    * 语法: const fnNew = fnOld.bind(obj)
    *
    * */
    // 普通函数的this
    // 根this指向window
    console.log(this)
    // 函数的this在没调用时指向window => 默认是window.fn
    function fn() {
        console.log(this)
    }
    fn()
    setTimeout(function () {
        console.log(this)
    } , 0)
    // button触发函数调用时指向button
    document.querySelector('button').addEventListener('click' , function () {
        console.log(this)
    })
    // 对象调用函数时指向对象
    const obj22 = {
        sayHi: function () {
            console.log(this)
        }
    }
    obj22.sayHi()
    // 箭头函数的this
    const user = {
        name: '小明',
        walk: () => {
            console.log(this)
        }
    }
    user.walk()

    // call方法改变箭头函数的this
    const obj33 = {
        uname: 'Black233'
    }
    function ffn() {
        console.log(this)
    }
    function ffn1(x , y) {
        console.log(this)
        this.uname = x + '' + y
        console.log(x + y)
    }
    ffn.call(obj33)
    ffn1.call(obj33 , 1 , 2)
    console.log(obj33)

    // apply方法改变箭头函数的this
    const obj44 = {
        age: 18
    }
    function ffn2(x , y) {
        console.log(this)
        console.log(x + y)
        this.age = x + y
    }
    ffn2.apply(obj44 , [1 , 2])
    console.log(obj44)
    // bind方法不会调用函数,但是能改变函数内部this指向
    const ffn3 = ffn2.bind(obj)
    ffn3(1,2)
</script>
</html>